﻿//From nRoute framework ver 0.4.5 

using System;
using System.Windows.Controls;
using System.ComponentModel;
using System.Globalization;
using System.Windows.Markup;
using System.Text;

namespace MoneyBook.ComponentModel {
    public static class TypeConverterHelper {

        public static object ConvertToType(object value, Type type) {
            if (value == null)
                return null;

            if (type.IsAssignableFrom(value.GetType()))
                return value;

            TypeConverter converter = TypeConverterHelper.GetTypeConverter(type);

            if (converter != null && converter.CanConvertFrom(value.GetType())) {

                value = converter.ConvertFrom(value);
                return value;
            }

            return null;
        }


        public static TypeConverter GetTypeConverter(Type type) {
            TypeConverterAttribute attribute = (TypeConverterAttribute)Attribute.GetCustomAttribute(type, typeof(TypeConverterAttribute), false);
            if (attribute != null) {
                try {
                    Type converterType = Type.GetType(attribute.ConverterTypeName, false);
                    if (converterType != null) {
                        return (Activator.CreateInstance(converterType) as TypeConverter);
                    }
                } catch {
                }
            }
            return new ExtStringConverter(type);
        }


        private class ExtStringConverter : TypeConverter {

            private Type type;

            public ExtStringConverter(Type type) {
                this.type = type;
            }

            public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {
                if ((sourceType != typeof(string)) && (sourceType != typeof(uint))) {
                    return base.CanConvertFrom(context, sourceType);
                }
                return true;
            }

            public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
                return ((typeof(IConvertible).IsAssignableFrom(this.type) && typeof(IConvertible).IsAssignableFrom(destinationType)) || base.CanConvertTo(context, destinationType));
            }

            public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) {

                string targetValue = value as string;

                if (targetValue != null) {
                    Type targetType = this.type;

                    if (targetType == typeof(bool)) {
                        return bool.Parse(targetValue);
                    } else if (targetType.IsEnum) {
                        return Enum.Parse(this.type, targetValue, false);
                    }

                    Type underlyingType = Nullable.GetUnderlyingType(this.type);
                    if (underlyingType != null) {
                        if (string.Equals(targetValue, "null", StringComparison.OrdinalIgnoreCase)) {
                            return null;
                        }
                        targetType = underlyingType;
                    } else if (targetType.IsGenericType) {
                        return base.ConvertFrom(context, culture, value);
                    }

                    StringBuilder builder = new StringBuilder();
                    builder.Append("<ContentControl xmlns='http://schemas.microsoft.com/client/2007' xmlns:c='" +
                        ("clr-namespace:" + targetType.Namespace +
                        ";assembly=" + targetType.Assembly.FullName.Split(new char[] { ',' })[0]) + "'>\n");
                    builder.Append("<c:" + targetType.Name + ">\n");
                    builder.Append(targetValue);
                    builder.Append("</c:" + targetType.Name + ">\n");
                    builder.Append("</ContentControl>");
                    ContentControl control = XamlReader.Load(builder.ToString()) as ContentControl;
                    if (control != null) {
                        return control.Content;
                    }
                } else if (value is uint) {
                    if (this.type == typeof(bool)) {
                        return (((uint)value) != 0);
                    }
                    if (this.type.IsEnum) {
                        return Enum.Parse(this.type, Enum.GetName(this.type, value), false);
                    }
                }
                return base.ConvertFrom(context, culture, value);
            }

            public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) {
                IConvertible convertible = value as IConvertible;
                if ((convertible != null) && typeof(IConvertible).IsAssignableFrom(destinationType)) {
                    return convertible.ToType(destinationType, CultureInfo.InvariantCulture);
                }
                return base.ConvertTo(context, culture, value, destinationType);
            }
        }
    }
}
